import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:convert/convert.dart';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart' as crypto;
import 'package:intl/intl.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:dio/dio.dart' as dio show FormData;
import 'package:intl/intl.dart';
import 'package:package_info_plus/package_info_plus.dart';
import '../../storage/pref_utils.dart';

import 'dio/dio_networker_impl.dart';
import 'net_data.dart';

/// 应用环境类型
enum AppEnvironment {
  /// 开发环境
  dev,

  /// 测试环境
  test,

  /// 生产环境
  prod,

  /// new 生产环境
  newProd,
}

// 发起网络请求的实际执行工具
// 不用直接使用NetWorker发起请求
abstract class NetWorker {
  // 实际发起网络请求的抽象方法，由具体实现定义
  Future<dynamic> realRequest<T>(
    String path, {
    String method = "POST",
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Map<String, dynamic>? headers,
  });
}

// ApiClient类：用于管理网络请求，包括网络请求基本参数，请求使用的NetWorker实例，请求防止并发
class ApiClient {
  PackageInfo? packageInfo;
  AndroidDeviceInfo? androidDeviceInfo;
  IosDeviceInfo? iosDeviceInfo;
  var apiDateFormat = DateFormat('yyyy-MM-dd'); // 输出：YYYY-MM-DD

  // 当前环境
  AppEnvironment _environment = AppEnvironment.newProd;

  // 获取当前环境
  AppEnvironment get environment => _environment;

  // 根据环境获取API基础URL
  // 114.116.105.252:8100
  String _getBaseUrlByEnvironment() {
    switch (_environment) {
      case AppEnvironment.dev:
        return "http://154.8.172.131:8100/";
      case AppEnvironment.test:
        return "http://114.116.105.252:8100/";
      case AppEnvironment.prod:
        return "http://114.116.105.252:8100/";
      case AppEnvironment.newProd:
        return "https://saapi.bld365.com/";
    }
  }

  // 设置环境并更新NetWorker的baseUrl
  void setEnvironment(AppEnvironment env) {
    _environment = env;
    _netWorker = DioNetWorker(_getBaseUrlByEnvironment());
  }

  // 根据当前环境创建NetWorker
  late NetWorker _netWorker;

  //ApiClient单例模式
  static final ApiClient _instance = ApiClient._internal();

  factory ApiClient() {
    return _instance;
  }

  ApiClient._internal() {
    // 初始化时根据默认环境创建NetWorker
    _netWorker = DioNetWorker(_getBaseUrlByEnvironment());
  }


  /// 获取通用参数
  Future<Map<String, String>> get appInfo async {
    packageInfo = packageInfo ?? await PackageInfo.fromPlatform();
    final connectivityResult = await Connectivity().checkConnectivity();
    String network = 'none';
    if (connectivityResult.contains(ConnectivityResult.wifi)) {
      network = 'WIFI';
    } else if (connectivityResult.contains(ConnectivityResult.mobile)) {
      network = '4G';
    }

    Map<String, String> map = {
      'os': Platform.isAndroid ? '1' : '2',
      'deviceNetType': network,
      'ts': "${DateTime.now().millisecondsSinceEpoch}",
    };

    var package = packageInfo;
    if (package != null) {
      map['verCode'] = package.buildNumber;
      map['verName'] = package.version;
    }

    DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
    if (Platform.isAndroid) {
      androidDeviceInfo = androidDeviceInfo ?? await deviceInfo.androidInfo;
      var androidInfo = androidDeviceInfo;
      if (androidInfo != null) {
        map['deviceBrand'] = androidInfo.brand;
        map['deviceModel'] = androidInfo.model;
        map['deviceOSVer'] = androidInfo.version.release;
        map['os_ver'] = androidInfo.version.release;
        map['phoneMac'] = androidInfo.id;
      }
    } else if (Platform.isIOS) {
      iosDeviceInfo = iosDeviceInfo ?? await deviceInfo.iosInfo;
      var iosInfo = iosDeviceInfo;
      if (iosInfo != null) {
        map['deviceBrand'] = 'Apple Inc';
        map['deviceModel'] = iosInfo.localizedModel;
        map['deviceOSVer'] = iosInfo.systemVersion;
        map['os_ver'] = iosInfo.systemVersion;
        map['phoneMac'] = iosInfo.identifierForVendor ?? '';
      }
    }

    var token = await PrefUtils().getToken();

    if (map['phoneMac'] == null) {
      map['phoneMac'] = token;
    }

    if (token != "") {
      map['token'] = token;
    }


    /// 获取定位信息
    // if (requestLoc != null) {
    //   var la = requestLoc?.latitude;
    //   var lo = requestLoc?.longitude;
    //   if (la != null) {
    //     map['latitude'] = "$la";
    //   }
    //   if (lo != null) {
    //     map['longitude'] = "$lo";
    //   }
    // }

    return map;
  }

  // 缓存Completer的Map，用于存储网络请求的Completer对象
  var _cacheCompleterMap = {};

  // 创建一个新的Completer，并根据key存储到缓存中
  Completer<NetData<T>> _createCompleter<T>(String key) {
    var complete = Completer<NetData<T>>();

    _cacheCompleterMap[key] = complete;
    return complete;
  }

  // 根据key从缓存中获取对应的Completer
  Completer<NetData<T>>? _getCompleter<T>(String key) {
    var complete = _cacheCompleterMap[key];
    return complete;
  }

  // 根据路径和数据计算一个唯一的key
  String _computeKey(String path, dynamic data) {
    // 处理FormData类型的特殊情况
    if (data is dio.FormData) {
      // 为FormData类型创建一个特殊的key，包含路径和时间戳
      // 这样每个FormData请求都会有一个唯一的key
      return crypto.md5
          .convert(utf8.encode(path +
              "_formdata_" +
              DateTime.now().millisecondsSinceEpoch.toString()))
          .toString();
    }

    // 尝试将数据转换为字符串，用于计算key
    var dataStr = "";
    try {
      if (data is Map) {
        dataStr = jsonEncode(data);
      }
    } catch (e) {
      print("Error encoding data for key computation: $e");
    }
    // 使用MD5算法计算最终的key
    return crypto.md5.convert(utf8.encode(path + dataStr)).toString();
  }

  // 从缓存中移除指定key的Completer
  void _removeCompleter(String key) {
    _cacheCompleterMap.remove(key);
  }

  // 发起网络请求的抽象方法
  Future<NetData<T?>> request<T>(
    String path, {
    String method = "POST",
    data,
    Map<String, dynamic>? queryParameters,
  }) async {
    // 如果data未定义，则初始化为空map
    data ??= <String, Object?>{};

    // 计算请求的唯一key
    String key = _computeKey(path, data);

    // 尝试从缓存中获取对应的Completer
    var comp = _getCompleter<T>(key);
    // 如果Completer存在且请求未完成，则直接返回缓存的Completer结果
    if (comp != null && !comp.isCompleted) {
      return comp.future;
    }

    // 创建一个新的Completer，并发起实际的网络请求
    var completer = _createCompleter<T>(key);

    (queryParameters ??= {}).addAll(await appInfo);
    dynamic realRequestData;
    if (method == 'POST') {
      //将appInfo中的全部key value对添加到options.queryParameters中
      //先判断data的类型 有可能是Map 也可能是FormData
      if (data == null) {
        realRequestData = {...await appInfo};
      } else {
        if (data is Map) {
          Map<String, dynamic> wrappedData = {...data};
          wrappedData.addAll(await appInfo);
          realRequestData = wrappedData;
        } else if (data is dio.FormData) {
          data.fields.addAll((await appInfo).entries);
          realRequestData = data;
        }
      }
    }

    // 请求完成后，完成Completer并从缓存中移除
    _netWorker
        .realRequest<T>(
      path,
      data: realRequestData,
      method: method,
      queryParameters: queryParameters,
    )
        .then((value) {
      NetData<T> result;
      if (value == null) {
        result = NetData<T>(code: "9000", desc: "网络请求失败", data: null);
      } else {
        //请求结果统一处理
        try {
          result = NetData<T>.fromJson(value);
        } catch (e) {
          result = NetData<T>(code: "9000", desc: e.toString(), data: null);
        }
      }
      completer.complete(result);
      _removeCompleter(key);
    }).catchError((e) {
      NetData<T> result =
          NetData<T>(code: "9000", desc: e.toString(), data: null);
      completer.complete(result);
      _removeCompleter(key);
    });
    return completer.future;
  }
}
